<template>
  <el-table :data="tableListData"
            ref="treeTable"
            :element-loading-text="elementLoadingText"
            :row-style='toggleDisplayTr'
            :border="border"
            :style="currentStyle"
            header-cell-class-name="common-table-header"
            @select="selectionChange"
            @selection-change="handleSelectionChange">
    <el-table-column v-if="showSelection"
                     type="selection"
                     width="55"
                     :selectable="selectTable"
                     align="center"></el-table-column>
    <el-table-column :label="firstLabelName" min-width="100" align="left" header-align="center">
      <template slot-scope="scope">
        <p :style="`margin-left: ${scope.row.__level * 20}px;margin-top:0;margin-bottom:0`"><i  @click="toggleFoldingStatus(scope.row)" class="permission_toggleFold" :class="toggleFoldingClass(scope.row)"></i>{{scope.row.dataCategoryName}}</p>
      </template>
    </el-table-column>
    <slot>
    </slot>
  </el-table>
</template>

<script>
  export default {
    props: {
      // 数据源（数组类型）
      sourceData: {
        type: Array,
        default: function () {
          return []
        }
      },
      // 根节点
      rootData: {
        type: Object,
        default: function () {
          return {}
        }
      },
      // 加载信息
      elementLoadingText: {
        type: String,
        default: function () {
          return '正在刷新'
        }
      },
      // 是否边框
      border: {
        type: Boolean,
        default: function () {
          return true
        }
      },
      // 表格样式
      styles: {
        type: String,
        default: function () {
          return 'width: 100%'
        }
      },
      // 是否显示选择列
      showSelection: {
        type: Boolean,
        default: function () {
          return false
        }
      },
      // 第一列树形数据的标题
      firstLabelName: {
        type: String,
        default: function () {
          return ''
        }
      },
      // 没有数据时是否显示根节点,默认显示根节点
      noDataFlag: {
        type: Boolean,
        default: function () {
          return false
        }
      },
      // 控制选择框禁用条件的方法
      selectTable: {
        type: Function,
        default: function () {
          return function ({ row, index }) {
            return true
          }
        }
      },
      // 数据关联主键,默认keyId和parentId关联
      keyId: {
        type: String,
        default: function () {
          return 'keyId'
        }
      },
      // 数据父节点主键,默认keyId和parentId关联
      parentId: {
        type: String,
        default: function () {
          return 'parentId'
        }
      }
    },
    data () {
      return {
        tableListData: [], // tableListData 展示数据的data
        foldList: [] // 该数组中的值 都会在列表中进行隐藏  死亡名单
      }
    },
    computed: {
      currentStyle: function () {
        return this.styles
      }
    },
    methods: {
      // Fn: toggleFoldingStatus
      // Intro: 切换展开 还是折叠
      // @params: 当前点击行的数据
      toggleFoldingStatus (params) {
        this.foldList.includes(params.__identity) ? this.foldList.splice(this.foldList.indexOf(params.__identity), 1) : this.foldList.push(params.__identity)
      },
      // Fn: toggleDisplayTr
      // Intro: 该方法会对每一行数据都做判断 如果foldList 列表中的元素 也存在与当前行的 __family列表中  则该行不展示
      toggleDisplayTr ({row, index}) {
        for (let i = 0; i < this.foldList.length; i++) {
          let item = this.foldList[i]
          // 如果foldList中元素存在于 row.__family中，则该行隐藏。  如果该行的自身标识等于隐藏元素，则代表该元素就是折叠点
          if (row.__family.includes(item) && row.__identity !== item) return 'display:none;'
        }
        return ''
      },
      // Fn: toggleFoldingClass
      // Intro: 如果子集长度为0，则不返回字体图标。
      // Intro: 如果子集长度为不为0，根据foldList是否存在当前节点的标识返回相应的折叠或展开图标
      // Intro: 关于class说明：permission_placeholder返回一个占位符，具体查看class
      // @params: 当前行的数据对象
      toggleFoldingClass (params) {
        return !params.children ? 'permission_placeholder' : (this.foldList.indexOf(params.__identity) === -1 ? 'el-icon-remove-outline' : 'el-icon-circle-plus-outline')
      },
      handleSelectionChange (val) {
        this.$emit('handleSelectionChange', val)
      },
      selectionChange (selection, row) {
        let $this = this
        let selected = selection.indexOf(row) !== -1
        if (row.children) {
          let rows = []
          this.tableListData.forEach(item => {
            if (item.__identity.indexOf(row.__identity) !== -1) {
              if ($this.selectTable(item)) {
                rows.push(item)
              }
            }
          })
          rows.forEach(row => {
            this.$refs.treeTable.toggleRowSelection(row, selected)
          })
        }
      },
      // Fn: formatList
      // Intro: 将数据调整为树形加载顺序，并增加关联标识
      // @params: parent 为当前累计的数组  也是最后返回的数组
      // @params: data 从后台取到的所有数据
      // @params: index 用于在递归中进行累计叠加 用于层级标识
      // @params: family 装有当前包含元素自身的所有父级 身份标识
      // @params: elderIdentity 父级的 唯一身份标识
      formatList (parent, data, parentId, index = 1, family = ['x_0'], elderIdentity = 'x_0') {
        let $this = this
        let flag = false
        data.forEach((x, i) => {
          if (x[this.parentId] === parentId) {
            // 设置 __level 标志位 用于展示区分层级
            $this.$set(x, '__level', index)
            // 设置 __family 为家族关系 为所有父级，包含本身在内
            $this.$set(x, '__family', [...family, elderIdentity + '_' + i])
            // 本身的唯一标识  可以理解为个人的身份证咯 一定唯一。
            $this.$set(x, '__identity', elderIdentity + '_' + i)
            parent.push(x)
            flag = true
            // 进行递归
            $this.formatList(parent, data, x[this.keyId], index + 1, [...family, elderIdentity + '_' + i], elderIdentity + '_' + i)
          }
        })
        // 设置children字段，用于区分是否为叶子节点
        if (flag) {
          data.forEach(item => {
            if (item[this.keyId] === parentId) {
              $this.$set(item, 'children', true)
            }
          })
        }
        return parent
      },
      loadTreeData (value) {
        let arr = []
        let obj = this.rootData
        this.$set(obj, '__level', 0)
        this.$set(obj, '__family', ['x_0'])
        this.$set(obj, '__identity', 'x_0')
        if (value.length > 0) {
          this.$set(obj, 'children', true)
        } else {
          this.$set(obj, 'children', false)
        }
        arr.push(obj)
        let data = this.objDeepCopy(value)
        if (this.noDataFlag && data.length === 0) {
          this.tableListData = []
        } else {
          this.tableListData = this.formatList(arr, data, obj[this.keyId])
        }
      },
      // 对象数组的深拷贝
      objDeepCopy (source) {
        var sourceCopy = source instanceof Array ? [] : {}
        for (var item in source) {
          sourceCopy[item] = typeof source[item] === 'object' ? this.objDeepCopy(source[item]) : source[item]
        }
        return sourceCopy
      }
    },
    watch: {
      sourceData: {
        deep: true,
        handler (value) {
          this.loadTreeData(value)
          this.$emit('treeDataChange', this.tableListData)
        }
      }
    }
  }
</script>

<style scoped>
  .permission_placeholder {
    content: ' ';
    display: inline-block;
    width: 16px;
    font-size: 16px;
  }

  .permission_toggleFold {
    vertical-align: middle;
    padding-right: 5px;
    font-size: 16px;
    cursor: pointer
  }
</style>
